﻿using Mapster;
using BJ.AuthEntity.DtoModels;
using BJ.AuthEntity.Models;
using BJ.AuthEntity.ViewModels;
using Syspetro.Core.DbAccessor;
using Syspetro.Deploy.FreeSqlDb;
using Syspetro.Deploy.Jwt;
using System;
using System.Threading.Tasks;
using BJ.AuthDomain.IService;
using Syspetro.Deploy.Managers;
using Syspetro.Core.AppDeal;
using Syspetro.Core.CommandBus;
using BJ.AuthDomain.Commands;
using Syspetro.Core;
using Microsoft.Extensions.Configuration;
using Syspetro.Core.HttpService;
using System.Net.Http;
using Syspetro.Core.Extensions;
using System.Collections.Generic;
using BJ.AuthEntity;
using Syspetro.Core.Encrypt;
using Syspetro.Core.Resources;
using System.Linq;

namespace BJ.AuthDomain.Service
{
    public class UserAuthService : EntityBaseService<UserAuth>, IUserAuthService
    {
        readonly IFreeSql _freeSql;
        readonly IJwtService _JwtService;
        readonly IRepository<UserAuth> repository;
        readonly IAuthorizationManager _authorization;
        readonly ICommandBus _command;
        readonly IUserService _userService;

        public UserAuthService(IFreeSql freeSql, IJwtService jwtservice, ICommandBus command, IAuthorizationManager authorization, IUserService userService
)
        {
            _freeSql = freeSql;
            _JwtService = jwtservice;
            _authorization = authorization;
            _command = command;
            this.repository = new FreeSqlRepository<UserAuth>(freeSql);
            _userService = userService;
        }
        public override IRepository<UserAuth> Repository
        {
            get
            {
                return repository;
            }
        }

        public async Task<SpActionResult<VM_Token>> LoginUser(VM_Login loginUser, UserAuth user = null)
        {
            if (user == null)
            {
                user = await _freeSql.Select<UserAuth>()
                    .Include(t => t.User)
                    .Where(t => t.Account == loginUser.Account)
                    .FirstAsync();
            }
            if (user != null)
            {
                if (!user.Enable)
                    return new SpActionResult<VM_Token> { Success = false, Msg = "用户不存在" };
                var check = _command.Send(new PswdCheckCommand { Pswd = loginUser.Password, Md5Pswd = user.Password });
                if (!check.Success)
                {
                    //密码更新,老用户密码加密方式导致更新账户不能登录
                    var newcheck = _command.Send(new PswdCheckCommand { Account = loginUser.Account, Pswd = loginUser.Password, Md5Pswd = user.Password });
                    if (newcheck.Success)
                    {
                        await DoChangePswd(new VM_ChangePswd { Pswd_New = loginUser.Password }, user);
                    }
                    else
                    {
                        return new SpActionResult<VM_Token> { Success = false, Msg = check.Msg };
                    }
                }
                //获取登录token
                var token = await GetLoginToken(user);
                if (token != null)
                    return new SpActionResult<VM_Token>(token);
                else
                    return new SpActionResult<VM_Token>(new VM_Token { Uid = user.Id }, SharedResource.RegisteSuccessfull);
            }
            return new SpActionResult<VM_Token> { Success = false, Msg = "用户不存在" };
        }
        public async Task<SpActionResult<VM_Token>> AuthLoginUser(VM_Login loginUser)
        {
            var user = await _freeSql.Select<UserAuth>()
                .Include(t => t.User)
                .Where(t => t.Account == loginUser.Account)
                .FirstAsync();
            if (user == null) return new SpActionResult<VM_Token> { Success = false, Msg = "用户不存在" };
            if (string.IsNullOrEmpty(loginUser.Code))
            {
                if (user.AccountType == (AccountType.Email | AccountType.SMS))
                {
                    var (bl, msg) = DoSendCode(user.AccountType, loginUser.Account);
                    return new SpActionResult<VM_Token> { Success = bl, Msg = msg };
                }
                else
                {
                    return await LoginUser(loginUser, user);
                }
            }
            else
            {
                var (bl, msg) = DoVerifyCode(user.AccountType, user.Account, loginUser.Code);
                if (bl)
                {
                    return await LoginUser(loginUser, user);
                }
                else
                {
                    return new SpActionResult<VM_Token> { Success = false, Msg = msg };
                }
            }
        }
        public async Task<SpActionResult<VM_Token>> Register(VM_Login_Register register)
        {
            var (bl, msg) = DoVerifyCode(register.AccountType, register.Account, register.ValidaCode);
            if (!bl)
                return new SpActionResult<VM_Token> { Success = false, Msg = msg };
            var userany = (await Repository.FindAsync(t => t.Account == register.Account)).FirstOrDefault();
            if (userany != null)
            {
                if (!userany.Enable)
                    return new SpActionResult<VM_Token> { Success = false, Msg = "注册失败" };
                return new SpActionResult<VM_Token> { Success = false, Msg = "该账号已经注册" };
            }
            if (Repository.Any(t => t.Account == register.Account))
            {
                return new SpActionResult<VM_Token> { Success = false, Msg = "该账号已经注册" };
            }
            var user = new User
            {
                Name = register.Name,
                Phone = register.AccountType == AccountType.SMS ? register.Account : null,
                Emil = register.AccountType == AccountType.Email ? register.Account : null
            };

            TeamOptions team = new();
            InternalApp.Configuration.Bind(nameof(TeamOptions), team);//邀请码验证
            if (team.MustBe && string.IsNullOrEmpty(register.InviteCode))
            {
                return new SpActionResult<VM_Token> { Success = false, Msg = "邀请码是必须的" };
            }
            if (!string.IsNullOrEmpty(register.InviteCode))
            {
                var FormParameter = new Dictionary<string, string>
                {
                    { "uid", user.Id.ToString() },
                    { "code", register.InviteCode }
                };
                var ress = _command.Send(new HttpCommand
                {
                    Url = team.Url,
                    HttpMethod = HttpMethod.Post,
                    FormParameter = FormParameter
                }).Get();
                if (!ress.Success)
                {
                    return new SpActionResult<VM_Token> { Success = false, Msg = ress.Msg };
                }
            }
            var pswd = _command.Send(new PswdMd5Command { Pswd = register.Password });
            if (!pswd.Success)
                return new SpActionResult<VM_Token> { Success = false, Msg = pswd.Msg };
            UserAuth authUser = new()
            {
                Password = pswd.Get().Data,
                Account = register.Account,
                AccountType = register.AccountType,
                User = user,
                Id = user.Id,
                RegisterTime = DateTime.Now,
                Enable = true
            };

            Repository.AddTrans(user);
            Repository.AddTrans(authUser);
            await Repository.SaveAsync;

            NewsOptions news = new();
            InternalApp.Configuration.Bind(nameof(NewsOptions), news);
            if (!string.IsNullOrEmpty(news.Register))
            {
                Guid[] uids = new Guid[] { authUser.Id };
                var ress = _command.Send(new HttpCommand
                {
                    Url = news.Url,
                    HttpMethod = HttpMethod.Post,
                    StrParameter = new { title = "欢迎加入诺亚算力", content = news.Register, userID = uids }.ToJson()
                });
            }
            //获取登录token
            var token = await GetLoginToken(authUser);
            if (token != null)
                return new SpActionResult<VM_Token>(token);
            else
                return new SpActionResult<VM_Token>(new VM_Token { Uid = authUser.Id }, SharedResource.RegisteSuccessfull);
        }
        public Task<string> RefreshToken(Guid tokenId)
        {
            return Task.FromResult(_JwtService.RefreshToken(tokenId));
        }
        public Task LogOut(Guid tokenid)
        {
            return Task.Run(() => { _JwtService.RemoveToken(tokenid); });
        }
        /// <summary>
        /// 获取用户详情
        /// </summary>
        /// <returns></returns>
        public async Task<SpActionResult<VM_User>> GetUserInfo()
        {
            var acc = _authorization.GetUserId;
            if (acc == Guid.Empty) return new SpActionResult<VM_User> { Success = false, Msg = "用户不存在" };
            var vm_User = await _userService.GetUserFull(acc);
            return new SpActionResult<VM_User>(vm_User);
        }
        /// <summary>
        /// 修改登录密码
        /// </summary>
        /// <param name="changePswd"></param>
        /// <returns></returns>
        public async Task<SpActionResult<bool>> ChangePswd(VM_ChangePswd changePswd)
        {
            var acc = _authorization.GetUserId;
            var user = await _freeSql.Select<UserAuth>()
                .Include(t => t.User)
                .Where(t => t.Id == acc)
                .FirstAsync();
            if (user == null) return new SpActionResult<bool> { Success = false, Msg = "用户不存在" };
            var check = _command.Send(new PswdCheckCommand { Pswd = changePswd.Pswd_Old, Md5Pswd = user.Password });
            if (!check.Success)
            {
                //密码更新,老用户密码加密方式导致更新账户不能登录
                var newcheck = _command.Send(new PswdCheckCommand { Account = user.Account, Pswd = changePswd.Pswd_Old, Md5Pswd = user.Password });
                if (!newcheck.Success)
                {
                    return new SpActionResult<bool> { Success = false, Msg = check.Msg };
                }
            }
            return new SpActionResult<bool>(await DoChangePswd(changePswd, user));
        }
        /// <summary>
        /// 忘记密码
        /// </summary>
        /// <param name="forget"></param>
        /// <returns></returns>
        public async Task<SpActionResult<VM_Token>> ForgetPswd(VM_Login_Forget forget)
        {
            if (forget.Password != forget.ConfirmPassword)
            {
                return new SpActionResult<VM_Token> { Success = false, Msg = "两次密码输入不一致" };

            }
            var authUser = await _freeSql.Select<UserAuth>().Include(t => t.User).Where(t => t.Account == forget.Account).FirstAsync();
            if (authUser == null)
            {
                return new SpActionResult<VM_Token> { Success = false, Msg = "该账号不存在" };
            }
            var (bl, msg) = DoVerifyCode(forget.AccountType, forget.Account, forget.ValidaCode);
            if (!bl)
                return new SpActionResult<VM_Token> { Success = false, Msg = msg };

            var pswd = _command.Send(new PswdMd5Command { Pswd = forget.Password });
            if (!pswd.Success)
                return new SpActionResult<VM_Token> { Success = false, Msg = pswd.Msg };
            authUser.Password = pswd.Get().Data;

            await Repository.UpdateAsync(authUser);

            //获取登录token
            var token = await GetLoginToken(authUser);
            if (token != null)
                return new SpActionResult<VM_Token>(token);
            else
                return new SpActionResult<VM_Token>(new VM_Token { Uid = authUser.Id }, SharedResource.RegisteSuccessfull);
        }
        /// <summary>
        /// 获取登录token
        /// </summary>
        /// <param name="authUser"></param>
        /// <returns></returns>
        private async Task<VM_Token> GetLoginToken(UserAuth authUser)
        {
            var userdto = authUser.Adapt<UserAuthDto>();
            userdto.UserId = authUser.Id;
            userdto.UserName = authUser.User.Name;
            var token = this._JwtService.GetToken(userdto);
            if (!string.IsNullOrEmpty(token.Item2))
            {
                authUser.LoginTime = DateTime.Now;
                await Repository.UpdateAsync(authUser, t => t.LoginTime);
                var vmUser = new VM_Token { Token = token.Item2, TokenId = token.Item1, Uid = authUser.Id };
                return vmUser;
            }
            return null;
        }

        private (bool, string) DoSendCode(AccountType accountType, string Account)
        {
            SpActionResult ver = accountType switch
            {
                AccountType.Email => _command.Send(new SendEmailCommand { Email = Account }),
                AccountType.SMS => _command.Send(new SendSMSCommand { Phone = Account }),
                _ => new SpActionResult() { Success = true },
            };
            return (ver.Success, ver.Msg);
        }
        private (bool, string) DoVerifyCode(AccountType accountType, string Account, string Code)
        {
            SpActionResult ver = accountType switch
            {
                AccountType.Email => _command.Send(new EmailVerifyCommand { Captcha = Code, Email = Account }),
                AccountType.SMS => _command.Send(new SMSVerifyCommand { Captcha = Code, Phone = Account }),
                _ => new SpActionResult() { Success = true },
            };
            return (ver.Success, ver.Msg);
        }
        private async Task<bool> DoChangePswd(VM_ChangePswd changePswd, UserAuth user)
        {
            var pswd = _command.Send(new PswdMd5Command { Pswd = changePswd.Pswd_New });
            if (!pswd.Success)
                return false;
            user.Password = pswd.Get().Data;
            if (await _freeSql.Update<UserAuth>().SetSource(user).UpdateColumns(t => t.Password).ExecuteAffrowsAsync() > 0)
                return true;
            return false;
        }
        public async Task<SpActionResult<Guid>> GetUserId(string Account)
        {
            if (Account.IsPhone())
            {
                var u = await _freeSql.Select<User>().Where(t => t.Phone == Account).FirstAsync();
                if (u != null)
                    return new SpActionResult<Guid>(u.Id);
            }
            else if (Account.IsEmail())
            {
                var u = await _freeSql.Select<User>().Where(t => t.Emil == Account).FirstAsync();
                if (u != null)
                    return new SpActionResult<Guid>(u.Id);
            }
            else
            {
                var u = await _freeSql.Select<UserAuth>().Where(t => t.Account == Account).FirstAsync();
                if (u != null)
                    return new SpActionResult<Guid>(u.Id);
            }
            return new SpActionResult<Guid> { Success = false, Msg = "未查询到该用户" };
        }

        public async Task<SpActionResult<bool>> ChangePhone(VM_ChangePhone changePhone)
        {
            var uid = _authorization.GetUserId;

            var blpuone = await _freeSql.Select<User>().AnyAsync(t => t.Phone == changePhone.Phone_New);
            if (blpuone) return new SpActionResult<bool> { Success = false, Msg = "该手机号码已经注册" };
            var user = await _freeSql.Select<User>().Include(t => t.Auth).Where(t => t.Id == uid).FirstAsync();
            if (user != null)
            {
                if (user.Phone == changePhone.Phone_New) return new SpActionResult<bool> { Success = false, Msg = "不能与原手机号一致" };
                var bl = _command.Send(new SMSVerifyCommand { Captcha = changePhone.Code, Phone = changePhone.Phone_New });
                if (bl.Success)
                {
                    if (user.Auth.AccountType == AccountType.SMS)
                    {
                        _freeSql.Update<User>().Set(a => a.Phone, changePhone.Phone_New).Set(a => a.Name, changePhone.Phone_New).Where(a => a.Id == uid).ExecuteAffrows();
                        _freeSql.Update<UserAuth>().Set(a => a.Account, changePhone.Phone_New).Where(a => a.Id == uid).ExecuteAffrows();
                    }
                    else
                    {
                        _freeSql.Update<User>().Set(a => a.Phone, changePhone.Phone_New).Where(a => a.Id == uid).ExecuteAffrows();
                    }
                    return new SpActionResult<bool>(true);
                }
                else
                {
                    return new SpActionResult<bool> { Success = false, Msg = "验证码错误" };
                }
            }
            else
                return new SpActionResult<bool> { Success = false, Msg = "异常用户" };
        }

        public async Task<SpActionResult<VM_TokenInfo>> LoginUserInfo(VM_Login loginUser, UserAuth user = null)
        {
            var res = await LoginUser(loginUser, user);
            if (!res.Success)
                return new SpActionResult<VM_TokenInfo> { Success = false, Msg = res.Msg };
            else
            {
                var vm_User = await _userService.GetUserFull(res.Data.Uid);
                return new SpActionResult<VM_TokenInfo>(new VM_TokenInfo { Info = vm_User, Token = res.Data });
            }
        }

        public async Task<SpActionResult<VM_TokenInfo>> RegisterInfo(VM_Login_Register register)
        {
            var res = await Register(register);
            if (!res.Success)
                return new SpActionResult<VM_TokenInfo> { Success = false, Msg = res.Msg };
            else
            {
                var vm_User = await _userService.GetUserFull(res.Data.Uid);
                return new SpActionResult<VM_TokenInfo>(new VM_TokenInfo { Token = res.Data, Info = vm_User });
            }
        }
        public async Task<SpActionResult<bool>> FreezeUser(Guid id)
        {
            var user = await _freeSql.Select<UserAuth>().Where(d => d.Id == id).ToOneAsync();
            if (user == null)
                return new SpActionResult<bool> { Success = false, Msg = "用户不存在" };
            if (!user.Enable)
            {
                return new SpActionResult<bool> { Success = false, Msg = "用户已经是冻结状态" };

            }
            user.Enable = false;
            if (await _freeSql.Update<UserAuth>().SetSource(user).UpdateColumns(t => t.Enable).ExecuteAffrowsAsync() > 0)
                return new SpActionResult<bool>(true);
            return new SpActionResult<bool> { Success = false, Msg = "冻结失败" };
        }
        public async Task<SpActionResult<bool>> ResumeUser(Guid id)
        {
            var user = await _freeSql.Select<UserAuth>().Where(d => d.Id == id).ToOneAsync();
            if (user == null)
                return new SpActionResult<bool> { Success = false, Msg = "用户不存在" };
            if (user.Enable)
            {
                return new SpActionResult<bool> { Success = false, Msg = "用户已经是正常状态" };

            }
            user.Enable = true;
            if (await _freeSql.Update<UserAuth>().SetSource(user).UpdateColumns(t => t.Enable).ExecuteAffrowsAsync() > 0)
                return new SpActionResult<bool>(true);
            return new SpActionResult<bool> { Success = false, Msg = "恢复失败" };
        }
    }
}
